package edu.cn.nlsde.tmfst.mlda;

/**
 * Created by dell-pc on 2016/4/9.
 */


/**
 * @author ffftzh
 * @ClassName: SLDA
 * @Description: SLDA的实现
 * @date 2016年3月6日 下午8:42:36
 */
public class SLDA {
//    private final String data_path;
//    private final double alpha;
//    private final double beta;
//    private final int iter_num;
//    private final int topic_num;
//    private final String outputPath;
//    private final String tag_path;
//
//    private DenseVector tagList = null;
//
//    private HashMap<String, Integer> wordMap = new HashMap<>();
//    private HashMap<Integer, String> id2Word = new HashMap<>();
//    HashMap<String, Integer> tag2Id = new HashMap<>();
//
//    private int[][] wordId_of_corpus = null;
//    private int[][] topicId_of_corpus = null;
//
//    private int[][] word_num_in_topic_word = null;
//    private int[] word_num_in_topic = null;
//    private int[][] word_num_in_doc_topic = null;
//    private int[] word_num_in_doc = null;
//    private double sigma = 1;
//    private DenseVector eta;
//
//
//    public SLDA(String data_path, String tag_path, int topic_num, int iter_num, double alpha, double beta, int threadId) {
//
//        this.alpha = alpha;
//        this.beta = beta;
//        this.iter_num = iter_num;
//        this.topic_num = topic_num;
//        this.data_path = data_path;
//        this.tag_path = tag_path;
//        this.outputPath = (new File(data_path)).getParentFile().getAbsolutePath() + "/SLDA_" + alpha + "_" + beta + "_" + topic_num + "/" + threadId + "/";
//        (new File(this.outputPath)).mkdirs();
//        print_parameter();
//    }
//
//    private void print_parameter() {
//        System.out.println("path:" + this.data_path
//                + "\talpha:" + this.alpha
//                + "\tbeta:" + this.beta
//                + "\titer_num:" + this.iter_num
//                + "\ttopic_num:" + this.topic_num
//        );
//    }
//
//    private void load_data() {
//        try {
//            BufferedReader reader = IOUtil.getReader(this.data_path);
//            String line;
//            ArrayList<int[]> tmpCorpus = new ArrayList<>();
//            while ((line = reader.readLine()) != null) {
//                String[] words = line.split("\\s+");
//                int[] oneDoc = new int[words.length];
//                for (int wordIndex = 0; wordIndex < words.length; wordIndex++) {
//                    if (!this.wordMap.containsKey(words[wordIndex])) {
//                        this.wordMap.put(words[wordIndex], this.wordMap.size());
//                        this.id2Word.put(this.wordMap.get(words[wordIndex]), words[wordIndex]);
//                    }
//                    oneDoc[wordIndex] = this.wordMap.get(words[wordIndex]);
//                }
//                tmpCorpus.add(oneDoc);
//            }
//            reader.close();
//
//            this.wordId_of_corpus = new int[tmpCorpus.size()][];
//            for (int docIndex = 0; docIndex < this.wordId_of_corpus.length; docIndex++) {
//                this.wordId_of_corpus[docIndex] = tmpCorpus.get(docIndex);
//            }
//
//            tagList = new DenseVector(wordId_of_corpus.length);
//
//            reader = IOUtil.getReader(this.tag_path);
//            line = null;
//            int docIndex = 0;
//            while ((line = reader.readLine()) != null) {
//                String[] words = line.split("\\s+");
//                if (!tag2Id.containsKey(words[0])) {
//                    tag2Id.put(words[0], tag2Id.size());
//                }
//
//                tagList.set(docIndex++, tag2Id.get(words[0]));
//            }
//            reader.close();
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//
//    }
//
//    private void init_model() {
//        this.topicId_of_corpus = new int[this.wordId_of_corpus.length][];
//
//        this.word_num_in_topic_word = new int[this.topic_num][this.wordMap.size()];
//        this.word_num_in_topic = new int[this.topic_num];
//        this.word_num_in_doc_topic = new int[this.wordId_of_corpus.length][this.topic_num];
//        this.word_num_in_doc = new int[this.wordId_of_corpus.length];
//
//        for (int docIndex = 0; docIndex < this.wordId_of_corpus.length; docIndex++) {
//            this.topicId_of_corpus[docIndex] = new int[this.wordId_of_corpus[docIndex].length];
//            this.word_num_in_doc[docIndex] = this.wordId_of_corpus[docIndex].length;
//            for (int wordIndex = 0; wordIndex < this.wordId_of_corpus[docIndex].length; wordIndex++) {
//                int wordId = this.wordId_of_corpus[docIndex][wordIndex];
//                int topicId = (int) (Math.random() * this.topic_num);
//
//                this.topicId_of_corpus[docIndex][wordIndex] = topicId;
//
//                this.word_num_in_topic_word[topicId][wordId] += 1;
//                this.word_num_in_topic[topicId] += 1;
//                this.word_num_in_doc_topic[docIndex][topicId] += 1;
//
//            }
//        }
//        Random random = new Random();
//        this.eta = new DenseVector(this.topic_num);
//        set_eta_sigma();
////        for(int topic_id = 0;topic_id<this.topic_num;topic_id++){
////            this.eta.set(topic_id, 0, Math.sqrt(5)*random.nextGaussian());
////        }
//    }
//
//    void set_eta_sigma() {
//        DenseMatrix A = new DenseMatrix(this.wordId_of_corpus.length, this.topic_num);
//        DenseMatrix K_D = new DenseMatrix(this.topic_num, this.wordId_of_corpus.length);
//        DenseMatrix K_K = new DenseMatrix(this.topic_num, this.topic_num);
//        DenseVector K_1 = new DenseVector(this.topic_num);
//        DenseMatrix D_1 = new DenseMatrix(this.wordId_of_corpus.length, 1);
//        DenseMatrix _1_D = new DenseMatrix(1, this.wordId_of_corpus.length);
//        try {
//            for (int docIndex = 0; docIndex < this.wordId_of_corpus.length; docIndex++) {
//                D_1.set(docIndex, 0, this.tagList.get(docIndex));
//                for (int topic_id = 0; topic_id < this.topic_num; topic_id++) {
//                    A.set(docIndex, topic_id, ((double) this.word_num_in_doc_topic[docIndex][topic_id]) / this.word_num_in_doc[docIndex]);
//                }
//            }
//            A.transpose(K_D);
//            K_D.mult(A, K_K);
//            K_D.mult(this.tagList, K_1);
//            K_K.solve(K_1, this.eta);
//            D_1.transpose(_1_D);
//            this.sigma = _1_D.mult(D_1, new DenseMatrix(1, 1)).get(0, 0)
//                    - _1_D.mult(A, new DenseMatrix(1, this.topic_num)).mult(this.eta, new DenseVector(1)).get(0);
//            this.sigma /= this.wordId_of_corpus.length;
//        } catch (Exception es) {
//            es.printStackTrace();
//        }
//
//    }
//
//    private void save_twords(int topWordNum) throws IOException {
//        BufferedWriter writer = IOUtil.getWriter(this.outputPath + "model-final.twords");
//
//        for (int topic_index = 0; topic_index < this.word_num_in_topic_word.length; topic_index++) {
//            HashMap<Integer, Double> oneLine = new HashMap<>();
//            for (int word_id = 0; word_id < this.word_num_in_topic_word[topic_index].length; word_id++) {
//                oneLine.put(word_id, ((double) this.word_num_in_topic_word[topic_index][word_id]) / this.word_num_in_topic[topic_index]);
//            }
//            List<Map.Entry<Integer, Double>> maplist = new ArrayList<>(oneLine.entrySet());
//
//            Collections.sort(maplist, new Comparator<Map.Entry<Integer, Double>>() {
//                public int compare(Map.Entry<Integer, Double> o1, Map.Entry<Integer, Double> o2) {
//                    return (o2.getValue().compareTo(o1.getValue()));
//                }
//            });
//
//            writer.write("Topic:" + topic_index + "\n");
//            int count = 0;
//            for (Map.Entry<Integer, Double> o1 : maplist) {
//                writer.write("\t" + this.id2Word.get(o1.getKey()) + "\t:" + o1.getValue() + "\n");
//                count++;
//                if (count > topWordNum) {
//                    break;
//                }
//            }
//            writer.write("\n");
//
//        }
//
//
//        writer.close();
//    }
//
//    private void save_wordMap() throws IOException {
//        BufferedWriter writer = IOUtil.getWriter(this.outputPath + "model-final.wordmap");
//        for (String key : this.wordMap.keySet()) {
//            writer.write(key + " " + this.wordMap.get(key));
//            writer.write("\n");
//        }
//        writer.close();
//    }
//
//    private void save_eta() throws IOException {
//        BufferedWriter writer = IOUtil.getWriter(this.outputPath + "model-final.eta");
//        for (VectorEntry item : eta) {
//            writer.write(item.get() + "\n");
//        }
//        writer.close();
//    }
//
//    private void save_tagMap() throws IOException {
//        BufferedWriter writer = IOUtil.getWriter(this.outputPath + "model-final.tagmap");
//        for (String key : this.tag2Id.keySet()) {
//            writer.write(key + " " + this.tag2Id.get(key));
//            writer.write("\n");
//        }
//        writer.close();
//    }
//
//    private void save_theta() throws IOException {
//        BufferedWriter writer = IOUtil.getWriter(this.outputPath + "model-final.theta");
//        for (int doc_index = 0; doc_index < topicId_of_corpus.length; doc_index++) {
//            for (int topic_id = 0; topic_id < this.topic_num; topic_id++) {
//                writer.write((this.alpha + this.word_num_in_doc_topic[doc_index][topic_id]) / (this.word_num_in_doc[doc_index] + this.alpha * this.topic_num) + " ");
//            }
//            writer.write("\n");
//        }
//        writer.close();
//    }
//
//    private void save_tassign() throws IOException {
//        BufferedWriter writer = IOUtil.getWriter(this.outputPath + "model-final.tassign");
//        for (int doc_index = 0; doc_index < this.topicId_of_corpus.length; doc_index++) {
//            for (int word_index = 0; word_index < this.topicId_of_corpus[doc_index].length; word_index++) {
//                writer.write(this.wordId_of_corpus[doc_index][word_index] + ":" + this.topicId_of_corpus[doc_index][word_index] + " ");
//            }
//            writer.write("\n");
//        }
//        writer.close();
//    }
//
//    private void save_phi() throws IOException {
//        BufferedWriter writer = IOUtil.getWriter(this.outputPath + "model-final.phi");
//        int topic_index = 0;
//        for (int[] line : this.word_num_in_topic_word) {
//            for (int words : line) {
//                writer.write((this.beta + words) / (this.word_num_in_topic[topic_index] + this.beta * this.wordMap.size()) + " ");
//            }
//            writer.write("\n");
//            topic_index++;
//        }
//        writer.close();
//
//    }
//
//    private int sample(int docIndex, int wordIndex) {
//        int wordId = this.wordId_of_corpus[docIndex][wordIndex];
//        int oldTopicId = this.topicId_of_corpus[docIndex][wordIndex];
//        int newTopicId = -1;
//
//        this.word_num_in_topic_word[oldTopicId][wordId] -= 1;
//        this.word_num_in_topic[oldTopicId] -= 1;
//        this.word_num_in_doc_topic[docIndex][oldTopicId] -= 1;
//        double[] topic_dot = dots(docIndex);
//        double[] p = new double[this.topic_num];
//        for (int k = 0; k < this.topic_num; k++) {
//            p[k] = (this.word_num_in_doc_topic[docIndex][k] + alpha)
//                    * (word_num_in_topic_word[k][wordId] + beta)
//                    / (word_num_in_topic[k] + word_num_in_topic_word[0].length * beta)
//                    * Math.exp(-1 * Math.pow((this.tagList.get(docIndex) - topic_dot[k]), 2) / 2 / this.sigma);
//        }
//
//        for (int k = 1; k < this.topic_num; k++) {
//            p[k] += p[k - 1];
//        }
//
//        double u = Math.random() * p[this.topic_num - 1];
//        for (int k = 0; k < this.topic_num; k++) {
//            if (u < p[k]) {
//                newTopicId = k;
//                break;
//            }
//
//        }
//
//        this.word_num_in_topic_word[newTopicId][wordId] += 1;
//        this.word_num_in_topic[newTopicId] += 1;
//        this.word_num_in_doc_topic[docIndex][newTopicId] += 1;
//
//        assert newTopicId > -1;
//        return newTopicId;
//
//    }
//
//    private double[] dots(int docIndex) {
//        double[] sum = new double[this.topic_num];
//        double all = 0;
//
//        for (int k = 0; k < this.topic_num; k++) {
//            all += this.word_num_in_doc_topic[docIndex][k] * this.eta.get(k);
//        }
//
//        for (int k = 0; k < this.topic_num; k++) {
//            sum[k] = (all + this.eta.get(k)) / this.wordId_of_corpus[docIndex].length;
//        }
//        return sum;
//    }
//
//
//    private void build_model() {
//
//        for (int iter = 0; iter < this.iter_num; iter++) {
//            long startTime = System.currentTimeMillis();
//
//            for (int docIndex = 0; docIndex < this.wordId_of_corpus.length; docIndex++) {
//                for (int wordIndex = 0; wordIndex < this.wordId_of_corpus[docIndex].length; wordIndex++) {
//                    try {
//                        this.topicId_of_corpus[docIndex][wordIndex] = this.sample(docIndex, wordIndex);
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//                if (docIndex % 100 == 0) {
////                    set_eta_sigma();
////                    System.out.println("finished process doc :" + docIndex);
//                }
//            }
//            set_eta_sigma();
//            System.out.println("finished iter :" + iter
//                    + "\tcost time:" + ((double) System.currentTimeMillis() - startTime) / 1000
//                    + "\tsigma:" + this.sigma);
//        }
//
//    }
//
//    private void save_result() {
//        try {
//            this.save_twords(20);
//            this.save_theta();
//            this.save_eta();
//            this.save_tagMap();
//            this.save_tassign();
//            this.save_wordMap();
//            this.save_phi();
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
//
//    public static void predict(String model_dir, String data_path, String tag_path, int topic_num, double alpha, double beta) throws IOException {
//        /////////////////////////////////////get theta////////////////////////////////////////////
////        String tassign_path = LDA_inference.infer_LDA(data_path, model_dir, 500, alpha, beta, "SLDA");
//        ArrayList<double[]> doc_topic = new ArrayList<>();
//        ArrayList<Integer> doc_length = new ArrayList<>();
////        BufferedReader reader = IOUtil.getReader(tassign_path);
//        BufferedReader reader = IOUtil.getReader(model_dir + "/model-final.tassign");
//        String line;
//        while ((line = reader.readLine()) != null) {
//            String[] lines = line.split("\\s+");
//            double[] oneDoc = new double[topic_num];
//            for (String item : lines) {
//                oneDoc[Integer.parseInt(item.split(":")[1])] += 1;
//            }
//            doc_length.add(lines.length);
//            doc_topic.add(oneDoc);
//        }
//        reader.close();
//        int doc_num = doc_topic.size();
//
//
//        DenseMatrix Z = new DenseMatrix(doc_num, topic_num);
//
//        for (int docIndex = 0; docIndex < doc_num; docIndex++) {
//            for (int topicId = 0; topicId < topic_num; topicId++) {
//                Z.set(docIndex, topicId, doc_topic.get(docIndex)[topicId] / doc_length.get(docIndex));
//            }
//        }
//        /////////////////////////////////////get eta////////////////////////////////////////////
//        DenseVector eta = new DenseVector(topic_num);
//        reader = IOUtil.getReader(model_dir + "/model-final.eta");
//        int topic_id = 0;
//        while ((line = reader.readLine()) != null) {
//            String[] words = line.split("\\s+");
//            eta.set(topic_id++, Double.parseDouble(words[0]));
//        }
//        reader.close();
//        /////////////////////////////////////get tag2id////////////////////////////////////////////
//        HashMap<String, Integer> tag2Id = new HashMap<>();
//        reader = IOUtil.getReader(model_dir + "/model-final.tagmap");
//
//        while ((line = reader.readLine()) != null) {
//            String[] lines = line.split("\\s+");
//            tag2Id.put(lines[0], Integer.parseInt(lines[1]));
//        }
//        reader.close();
//        /////////////////////////////////////get taglist////////////////////////////////////////////
//        DenseVector tagList = new DenseVector(doc_num);
//        reader = IOUtil.getReader(tag_path);
//
//        int docIndex = 0;
//        while ((line = reader.readLine()) != null) {
//            String[] words = line.split("\\s+");
//            tagList.set(docIndex++, tag2Id.get(words[0]));
//        }
//        reader.close();
//
//        ////////////////////////////////////////////////////////////////////////////////////////////
//        DenseVector predict_tag = new DenseVector(doc_num);
//        Z.mult(eta, predict_tag);
//        int sum = 0;
//        for (int i = 0; i < doc_num; i++) {
//            if (Math.abs(tagList.get(i) - predict_tag.get(i)) < 0.5 || predict_tag.get(i) > 6 || predict_tag.get(i) < 0) {
//                sum++;
//            } else {
//                System.out.println(predict_tag.get(i) + "\t" + tagList.get(i));
//            }
//
//        }
//        System.out.println(sum);
//        System.out.println(((double) sum) / tagList.size());
//
//
//    }
//
//    @Override
//    public void run() {
//        this.load_data();
//        this.init_model();
//        this.build_model();
//        this.save_result();
//    }
//
//    public static void build_SLDA_Model(String data_path, String tagPath, int topic_num, int iter_num, double alpha, double beta, int threadNum) {
//
//        ExecutorService service = Executors.newCachedThreadPool();
//        for (int threadId = 0; threadId < threadNum; threadId++) {
//            edu.cn.nlsde.tmfst.mlda.SLDA model = new edu.cn.nlsde.tmfst.mlda.SLDA(data_path, tagPath, topic_num, iter_num, alpha, beta, threadId);
//            service.submit(model);
//        }
//        service.shutdown();
//
//    }


}
